import {
  AmbientLight,
  BoxGeometry,
  Group,
  Mesh,
  MeshLambertMaterial,
  PerspectiveCamera,
  PointLight,
  Scene,
  Vector2,
  WebGLRenderer,
  Cache,
  Raycaster
} from './lib/three.module'
import { TrackballControls } from './lib/TrackballControls.js'
import { OrbitControls } from './lib/OrbitControls.js'
import MeshCover from './meshCover'

const TRACKBALL_CONTROLS = 1
const ORBIT_CONTROLS = 2

export default class ThreeManager {
  constructor(sweeper) {
    let scope = this
    //资源管理
    //模型具有的属性know,flag,floor,visible
    this.modules = [] //1000个模型对象
    this.material = { cover: undefined, default: undefined } //材质
    this.geometry = { box: undefined } //几何体
    this.mesh = { cover: undefined } //其他网格对象
    this.light = { light1: undefined, light2: undefined, ambient: undefined }
    this.raycaster = undefined //射线
    this.numCovers = [] //每个包含材质的面
    this.hoverMesh = undefined //指向当前选择的方块

    //初始化基本参数
    this.limit = 0
    this.winSize = {
      winWidth: window.innerWidth,
      winHeight: window.innerHeight
    }
    this.moduleSize = 44
    this.themeColor = sweeper.themeColor
    let diff = sweeper.difficulty
    let settings = sweeper.settings
    let winSize = this.winSize
    let moduleSize = this.moduleSize

    this.meshCover = new MeshCover(this)

    //创建场景对象
    this.scene = new Scene()
    this.renderer = new WebGLRenderer({
      canvas: document.getElementById('webgl'),
      antialias: true
    })
    this.mouse = new Vector2(-1, -1)
    this.camera = new PerspectiveCamera(45, winSize.winWidth / winSize.winHeight, 1, moduleSize * 150)
    this.light.light1 = new PointLight(0xffffff, 1)
    this.light.light2 = new PointLight(0xffffff, 1)
    this.light.ambient = new AmbientLight(0x444444)

    //进行场景布局
    let camera = this.camera
    let scene = this.scene
    let light1 = this.light.light1
    let light2 = this.light.light2
    light1.position.set(moduleSize * 20, moduleSize * 25, moduleSize * 22)
    light2.position.set(-moduleSize * 20, -moduleSize * 25, -moduleSize * 22)

    scene.add(light1)
    scene.add(light2)
    scene.add(this.light.ambient)
    camera.position.set(moduleSize * 22, moduleSize * 25, moduleSize * 22)
    camera.lookAt(scene.position)

    //初始化模型对象
    this.group = new Group()
    this.geometry.box = new BoxGeometry(moduleSize * 0.96, moduleSize * 0.96, moduleSize * 0.96)
    // this.material.cover = new MeshLambertMaterial({ color: 0xffffff })
    this.material.default = new MeshLambertMaterial({ color: parseInt(this.themeColor.color_md, 16) }) //此处可以进行皮肤定制
    // this.mesh.cover = new Mesh(this.geometry.box, this.material.cover)

    //进行模型布局
    let group = this.group
    // this.material.cover.transparent = true
    // this.material.cover.opacity = 0.2
    // this.mesh.cover.visible = false
    // scene.add(this.mesh.cover)

    //遍历xyz的方块组
    if (!diff.ux) diff = { ux: 10, uy: 10, uz: 10 }
    for (let x = 0; x < diff.ux; x++) {
      let groupX = new Group()
      groupX.position.set(x * moduleSize, 0, 0)
      for (let y = 0; y < diff.uy; y++) {
        let groupXY = new Group()
        groupXY.position.set(0, y * moduleSize, 0)
        for (let z = 0; z < diff.uz; z++) {
          let mesh = new Mesh(this.geometry.box, this.material.default)
          mesh.position.set(0, 0, z * moduleSize)
          mesh.name = (x > 9 ? '' : '0') + x + (y > 9 ? '' : '0') + y + (z > 9 ? '' : '0') + z
          mesh.know = false
          groupXY.add(mesh)
          this.modules.push(mesh)
        }
        groupX.add(groupXY)
      }
      group.add(groupX)
    }
    group.position.set((-(diff.ux - 1) / 2) * moduleSize, (-(diff.uy - 1) / 2) * moduleSize, (-(diff.uz - 1) / 2) * moduleSize)
    scene.add(this.group)

    //初始化渲染器
    this.renderer.setSize(winSize.winWidth, winSize.winHeight)
    let bgColor = parseInt(this.themeColor.color_bg, 16)
    if(settings.bgChange){
      let deep = diff.mineNum/(diff.ux*diff.uy*diff.uz)
      if(diff.diff==0){
        switch(true){
          case deep<=0.1:deep = 0 
          break;
          case deep<=0.2:deep = 1
          break;
          case deep<=0.3:deep = 2
          break;
          case deep<=0.4:deep = 3
          break;
          default:deep = 4
        }
      }else{
        deep = diff.diff-1
      }
      bgColor = bgColor - parseInt('0x00'+deep+'0'+deep+'0')
    }
    this.renderer.setClearColor(bgColor, 1)
    //初始化控制器
    switch (settings.controller) {
      case TRACKBALL_CONTROLS:
        this.controls = new TrackballControls(camera, this.renderer.domElement)
        this.controls.staticMoving = settings.staticMoving //禁用阻尼
        break
      case ORBIT_CONTROLS:
        this.controls = new OrbitControls(camera, this.renderer.domElement)
        break
      default:
        throw new Error('settings controller is null:' + settings.controller)
    }
    let controls = this.controls
    controls.rotateSpeed = parseFloat(settings.sensitive.xz)
    controls.zoomSpeed = parseFloat(settings.sensitive.sf)
    controls.panSpeed = parseFloat(settings.sensitive.py)
    let counter = sweeper.counter
    render()
    // console.log(this.renderer.info)

    function render() {
      let timeRunner = sweeper.gameLine.timeRunner
      scope.animationId = requestAnimationFrame(render)
      //更新显示文本内容
      document.getElementById('countNum').innerText = counter.countNum
      if (timeRunner == 0) {
        document.getElementById('timeRunner').innerText = '点击计时'
      } else {
        let ms = timeRunner % 100
        let ss = parseInt(timeRunner / 100) % 60
        let mm = parseInt(timeRunner / 6000) % 60
        let hh = parseInt(timeRunner / 360000)
        if (hh > 0) {
          document.getElementById('timeRunner').innerText =
            (hh > 9 ? '' : '0') + hh + ':' + (mm > 9 ? '' : '0') + mm + ':' + (ss > 9 ? '' : '0') + ss
        } else {
          document.getElementById('timeRunner').innerText =
            (mm > 9 ? '' : '0') + mm + ':' + (ss > 9 ? '' : '0') + ss + ':' + (ms > 9 ? '' : '0') + ms
        }
      }
      //限制帧数
      let fps = 5 - (settings.fps % 15)
      scope.limit = (scope.limit + 1) % fps
      if (scope.limit == 0) {
        if (controls) {
          controls.update()
        }
        scope.renderer.render(scope.scene, scope.camera)
      }
    }
  }
  //射线捕获模型并且刷新高亮
  mouseChange() {
    // let group = this.group
    // let strongBox = this.mesh.cover
    if (!this.raycaster) {
      this.raycaster = new Raycaster()
    }
    let raycaster = this.raycaster
    raycaster.setFromCamera(this.mouse, this.camera)
    const intersects = raycaster.intersectObjects(this.modules)
    //移动方块并显示
    if (intersects[0]) {
      for (let item of intersects) {
        if (item.object.visible) {
          this.hoverMesh = item.object
          // strongBox.position.set(
          //   this.hoverMesh.parent.parent.position.x + group.position.x,
          //   this.hoverMesh.parent.position.y + group.position.y,
          //   this.hoverMesh.position.z + group.position.z
          // )
          // strongBox.visible = true
          break
        }
        // strongBox.visible = false
        this.hoverMesh = undefined
      }
    } else {
      // strongBox.visible = false
      this.hoverMesh = undefined
    }
  }
  dispose() {
    let scope = this
    cancelAnimationFrame(this.animationId)
    function disposeList(list) {
      for (let index in list) {
        // console.log(list[index].child == undefined)
        if (list[index]?.child?.length > 0) {
          disposeList(list[index].child)
        }
        if (list[index]?.dispose) {
          list[index].dispose()
        }
        if (list[index]?.map?.dispose) {
          list[index].map.dispose()
        }
      }
    }
    for (let g1 of scope.group.children) {
      for (let g2 of g1.children) {
        g2.clear()
      }
      g1.clear()
    }
    scope.group.clear()
    // console.log(scope.group)
    disposeList(scope.material)
    disposeList(scope.geometry)
    disposeList(scope.numCovers)
    scope.controls.dispose()
    // console.log(scope.renderer.info)
    Cache.clear()
    scope.scene.clear()
    scope.renderer.dispose()
    scope.renderer.forceContextLoss()
    // console.log(scope.renderer.info)
  }
  refresh(){
    //清除无用资源

    //模型具有的属性know,flag,floor,visible
    for(let obj of this.modules){
      obj.know = false
      obj.flag = false
      obj.floor = false
      obj.visible = true
      obj.material = this.material.default
    }
    // this.mesh.cover.visible = false
    this.controls.reset()
  }
}
